/*****************************************************************
*
*	Article:
*		How to enumerate all the services on Windows
*
*	Authors:
*		Miles Chen (stainboyx@hotmail.com)
*
*	Reference:
*		http://msdn.microsoft.com/en-us/library/ms684323(VS.85).aspx
*		http://msdn.microsoft.com/en-us/library/ms682640(VS.85).aspx
*
*	Build and Run:
*		cl /EHsc /Fosimple /DUNICODE cpp-enumerate-win32-services.cpp & simple
*
*****************************************************************/
#include <Windows.h>
#pragma comment(lib, "Kernel32.lib")
#pragma comment(lib, "Advapi32.lib")
#pragma comment(lib, "Shell32.lib")

#include <iostream>
#include <fstream>
#include <string>
#include <memory>

using namespace std;


unique_ptr<string> U2A(const wchar_t* text)
{
	int length = wcslen(text);
	int nChars = WideCharToMultiByte(
		CP_UTF8,
		0,
		text,
		length,
		NULL,
		0,
		NULL,
		NULL);
	if (nChars == 0) return NULL;

	char* buffer = new char[nChars + 1];
	::WideCharToMultiByte(
		CP_UTF8,
		0,
		text,
		length,
		buffer,
		nChars,
		NULL,
		NULL); 
	buffer[nChars] = '\0';

	unique_ptr<string> s(new string(buffer));
	delete[] buffer;
	return s;
}



int main()
{
	SC_HANDLE scHandle;
	DWORD cbBytesNeeded;
	DWORD cbServicesReturned;
	DWORD cbResumeHandle = 0;
	
	//http://msdn.microsoft.com/en-us/library/ms684323(VS.85).aspx
	scHandle = OpenSCManagerW(L".", SERVICES_ACTIVE_DATABASE, SC_MANAGER_ENUMERATE_SERVICE);
	if(scHandle)
	{
		//http://msdn.microsoft.com/en-us/library/ms682640(VS.85).aspx
		if(!EnumServicesStatusExW(scHandle, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, 
				NULL, 0, &cbBytesNeeded, &cbServicesReturned, &cbResumeHandle, NULL)
			&& GetLastError() == ERROR_MORE_DATA)
		{
			LPVOID lpServices = malloc(cbBytesNeeded);
			cbResumeHandle = 0;

			if(EnumServicesStatusExW(scHandle, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, 
				(LPBYTE)lpServices, cbBytesNeeded, &cbBytesNeeded, &cbServicesReturned, &cbResumeHandle, NULL))
			{
				ofstream os;
				os.open(L"services.csv");
				os << "ServiceName,DisplayName,ProcessId,Status" << endl;

				LPENUM_SERVICE_STATUS_PROCESS p = (LPENUM_SERVICE_STATUS_PROCESS)lpServices;
				for(int i=0; i<(int)cbServicesReturned; i++, p++)
				{
					os << *U2A(p->lpServiceName).get() << "," << *U2A(p->lpDisplayName).get() <<
						"," << p->ServiceStatusProcess.dwProcessId << ","
						<< p->ServiceStatusProcess.dwCurrentState << endl;
				}

				os.close();
				ShellExecuteW(NULL, NULL, L"excel", L"services.csv", NULL, SW_SHOW);
			}
			else
			{
				cout << "Failed to enum system services, error code=" << GetLastError() << endl;
			}

			free(lpServices);
		}
		else
		{
			cout << "Failed to enum service count" << endl;
		}

		CloseServiceHandle(scHandle);
	}
	else
	{
		cout << "Failed to OpenSCManager with permission<SC_MANAGER_ENUMERATE_SERVICE>" << endl;
	}

	return 0;
}